<%@ WebHandler Class="JayrockWeb.PhoneBook"  Language="C#" %>

using System;
using System.Collections;
using System.Security.Principal;
using Anvil.Core;
using Anvil.Core.Helpers;
using Anvil.Extras.Spring;
using Jayrock.JsonRpc;
using Jayrock.JsonRpc.Web;
using PhoneBook.Core;
using Spring.Context;

namespace JayrockWeb
{
    /// <summary>
    /// Business Facade for Phonebook application.
    /// </summary>
    public class PhoneBook : JsonRpcHandler
    {

        /// <summary>
        /// Simple "Hello World" method for low-level testing.
        /// </summary>
        /// <returns></returns>
        [JsonRpcMethod("hello", Idempotent = true)]
        [JsonRpcHelp("Simple method that returns 'Hello World!' for low-level testing.")]
        public string hello()
        {
            return "Hello World!";
        }        
        
        private IRequestCatalog catalog = null;

        private IRequestCatalog GetCatalog()
        {
            if (catalog == null)
            {
                IApplicationContext factory = Objects.Factory();
                catalog = factory.GetObject(App.CATALOG_KEY) as IRequestCatalog;
                if (catalog == null)
                    throw new Exception("PhoneBook: GetCatalog()==null");
            }
            return catalog;
        }
        
        private RequestContext Execute(string command)
        {
            return (RequestContext) GetCatalog().ExecuteRequest(command);            
        }

        private void Execute(IViewHelper helper)
        {
            helper.Execute();
            if (helper.HasFault) throw helper.Fault;
            if (helper.HasAlerts) throw new Exception(helper.AlertsText);
        }

        /// <summary>
        /// Remove machine name from the string returned by authenticated WindowsIdentity.
        /// </summary>
        /// <param name="input">WindowsIdentity.GetCurrent().Name</param>
        /// <returns>User name without machine name prefix</returns>
        private string Conform(string input)
        {
            const int NOT_FOUND = -1;
            string output;
            int pos = input.LastIndexOf('\\');
            if (pos == NOT_FOUND) output = input;
            else output = input.Substring(pos+1);            
            return output;
        }

        
        /// <summary>
        /// Returns a profile for authenticated user or a guest profile.
        /// </summary>
        /// <returns></returns>
        [JsonRpcMethod(App.PROFILE, Idempotent = true)]
        [JsonRpcHelp("Returns a profile for authenticated user or a guest profile.")]
        public AppEntry profile()
        {
            WindowsIdentity id = WindowsIdentity.GetCurrent();
            if (!id.IsAuthenticated)
            {
                AppEntry guest = new AppEntry();
                guest.user_name = App.GUEST;
                return guest;
            }

            IViewHelper helper = GetCatalog().GetHelperFor(App.ENTRY);
            helper.Criteria[App.USER_NAME] = Conform(id.Name);
            Execute(helper);
            AppEntry entry = new AppEntry(helper.Criteria);
            return entry;
        }

        
         /// <summary>
         /// Convenience method to process name query.
         /// </summary>
         /// <param name="context"></param>
         /// <returns></returns>
        private string[] names(RequestContext context)
        {
            KeyValueList list = context.Outcome as KeyValueList;
            if (list == null) return null; // FIXME: Better error handling

            ArrayList names = new ArrayList(list.Count);
            foreach (KeyValue k in list)
            {
                names.Add(k.Value);
            }
            return (string[])names.ToArray(typeof(String));
        }
            
        ///<summary>
        /// Returns Last Name List as an array.
        ///</summary>
        ///<returns>An array representing the list of distinct last names.</returns>
        [JsonRpcMethod(App.LAST_NAME_LIST, Idempotent = true)]
        [JsonRpcHelp("Returns Last Name List as an array.")]
        public string[] last_name_list()
        {            
            RequestContext context = Execute(App.LAST_NAME_LIST);
            return names(context);
        }

        ///<summary>
        /// Returns First Name List as an array.
        ///</summary>
        ///<returns>An array representing the list of distinct last names.</returns>
        [JsonRpcMethod(App.FIRST_NAME_LIST, Idempotent = true)]
        [JsonRpcHelp("Returns First Name List as an array.")]
        public string[] first_name_list()
        {
            RequestContext context = Execute(App.FIRST_NAME_LIST);
            return names(context);
        }

        ///<summary>
        /// Returns Extension List as an array.
        ///</summary>
        ///<returns>An array representing the list of extensions.</returns>
        [JsonRpcMethod(App.EXTENSION_LIST, Idempotent = true)]
        [JsonRpcHelp("Returns Extension List as an array.")]
        public string[] extension_list()
        {
            RequestContext context = Execute(App.EXTENSION_LIST);
            return names(context);
        }

        ///<summary>
        /// Returns User Name List as an array.
        ///</summary>
        ///<returns>An array representing the list of user names.</returns>
        [JsonRpcMethod(App.USER_NAME_LIST, Idempotent = true)]
        [JsonRpcHelp("Returns User Name List as an array.")]
        public string[] user_name_list()
        {
            RequestContext context = Execute(App.USER_NAME_LIST);
            return names(context);
        }

        ///<summary>
        /// Returns Hired List as an array.
        ///</summary>
        ///<returns>An array representing the list of hire dates.</returns>
        [JsonRpcMethod(App.HIRED_LIST, Idempotent = true)]
        [JsonRpcHelp("Returns Hired List as an array.")]
        public string[] hired_list()
        {
            RequestContext context = Execute(App.HIRED_LIST);
            return names(context);
        }

        ///<summary>
        /// Returns Hours List as an array.
        ///</summary>
        ///<returns>An array representing the list of distinct hours per week settings.</returns>
        [JsonRpcMethod(App.HOURS_LIST, Idempotent = true)]
        [JsonRpcHelp("Returns hours List as an array.")]
        public string[] hours_list()
        {
            RequestContext context = Execute(App.HOURS_LIST);
            return names(context);
        }
        
        private AppEntryList get_entry_list() {
            IViewHelper helper = GetCatalog().GetHelperFor(App.ENTRY_LIST);
            Execute(helper);
            AppEntryList list = helper.Outcome as AppEntryList;
            return list;            
        }
        
        ///<summary>
        /// Returns Entry List as an AppEntryList.
        ///</summary>
        ///<returns>A list of objects representing the list of directory entries</returns>
        [JsonRpcMethod(App.ENTRY_LIST, Idempotent = true)]
        [JsonRpcHelp("Returns the complete directory as an array of formatted IDictionary objects.")]
        public AppEntryList entry_list()
        {
            return get_entry_list();
        }

        ///<summary>
        /// Returns Entry List as an AppEntryList.
        ///</summary>
        ///<returns>An array representing the list of directory entries</returns>
        [JsonRpcMethod("entry_list_array", Idempotent = true)]
        [JsonRpcHelp("Returns the complete directory as an array of strings.")]
        public object[] entry_list_array()
        {

             IList keys = new ArrayList(8);
                keys.Add(App.ENTRY_KEY);
                keys.Add(App.LAST_NAME);
                keys.Add(App.FIRST_NAME);
                keys.Add(App.EXTENSION);
                keys.Add(App.USER_NAME);
                keys.Add(App.EDITOR);
                keys.Add(App.HIRED);
                keys.Add(App.HOURS);
            
            object[] result = get_entry_list().ToStringArray(keys);
            return result;            
        }

        /// <summary>
        /// Returns an entry by key.
        /// </summary>
        /// <param name="key"></param>
        /// <returns>Entry corresponding to the given key</returns>
        [JsonRpcMethod(App.ENTRY, Idempotent = true)]
        [JsonRpcHelp("Returns an entry by key.")]
        public AppEntry entry(string key)
        {
            IViewHelper helper = GetCatalog().GetHelperFor(App.ENTRY);
            helper.Criteria[App.ENTRY_KEY] = key;
            Execute(helper);
            AppEntry entry = new AppEntry(helper.Criteria);
            return entry;
        }

        /// <summary>
        /// Saves the entry, insert or updating as appropriate. 
        /// If the key value is provided, the corresponding entry is upcated. 
        /// Otherwise, a new entry is added.
        /// </summary>
        /// <param name="input">Entry values to save</param>
        /// <returns></returns>
        [JsonRpcMethod(App.ENTRY_SAVE, Idempotent = false)]
        [JsonRpcHelp("Saves the entry, insert or updating as appropriate.")]
        public AppEntry entry_save(IDictionary input)
        {
            IViewHelper helper = GetCatalog().GetHelperFor(App.ENTRY_SAVE);
            helper.Read(input,true);
            Execute(helper);
            AppEntry entry = new AppEntry(helper.Criteria);
            return entry;
        }

        /// <summary>
        /// Deletes an entry by key.
        /// </summary>
        /// <param name="key">Key corresponding to entry to delete.</param>
        /// <returns>Key for deleted entry (as given) and item count</returns>
        [JsonRpcMethod(App.ENTRY_DELETE, Idempotent = false)]
        [JsonRpcHelp("Deletes an entry by key.")]
        public AppEntry entry_delete(string key)
        {
            IViewHelper helper = GetCatalog().GetHelperFor(App.ENTRY_DELETE);
            helper.Criteria[App.ENTRY_KEY] = key;
            Execute(helper);
            AppEntry entry = new AppEntry(helper.Criteria);
            return entry;
        }
    
    }
}